const fs = require('fs');
const multer = require('multer');
const config = require('../../config');
const { getLogger } = require('../logger');
const logger = getLogger('middlewares.fileMiddleware');
const { badRequest, serverError } = require('../utils/response');

/**
 * 确保上传目录存在
 * @param {string} dirPath - 目录路径
 */
const ensureUploadDir = (dirPath) => {
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath, { recursive: true });
  }
};

/**
 * 上传错误处理包装器
 * @param {Function} uploadMiddleware - multer上传中间件或处理函数
 * @returns {Function} - 包装后的中间件函数
 */
const uploadWrapper = (uploadMiddleware) => {
  return (req, res, next) => {
    // 检查是否是函数且需要作为中间件调用
    if (typeof uploadMiddleware === 'function') {
      try {
        // 如果是异步函数，使用Promise处理
        const result = uploadMiddleware(req, res, (err) => {
          if (err) {
            logger.error('文件上传错误', { error: err.message });
            return badRequest(req, res, err.message || '文件上传失败');
          }
          next();
        });
        
        // 如果返回的是Promise（异步函数），处理其可能的错误
        if (result && typeof result.then === 'function') {
          result.catch(err => {
            logger.error('文件上传异步错误', { error: err.message });
            return serverError(req, res, '文件处理失败');
          });
        }
      } catch (err) {
        logger.error('文件上传包装器错误', { error: err.message });
        return badRequest(req, res, '文件上传处理失败');
      }
    } else {
      next();
    }
  };
};

/**
 * 文件大小验证中间件
 * @param {number} maxSize - 最大文件大小（字节）
 * @returns {Function} - 中间件函数
 */
const validateFileSize = (maxSize) => {
  return (req, res, next) => {
    if (!req.file && !req.files) {
      return next();
    }

    // 处理单个文件
    if (req.file && req.file.size > maxSize) {
      return badRequest(req, res, `文件大小超过限制，最大允许 ${(maxSize / (1024 * 1024)).toFixed(2)}MB`);
    }

    // 处理多个文件（如果需要）
    if (req.files && Array.isArray(req.files)) {
      const oversizedFile = req.files.find(file => file.size > maxSize);
      if (oversizedFile) {
        return badRequest(req, res, `文件 ${oversizedFile.originalname} 大小超过限制，最大允许 ${(maxSize / (1024 * 1024)).toFixed(2)}MB`);
      }
    }

    next();
  };
};

/**
 * 检查文件是否存在的中间件
 * @returns {Function} - 中间件函数
 */
const ensureFileExists = () => {
  return (req, res, next) => {
    if (!req.file && !req.files) {
      return badRequest(req, res, '没有文件被上传');
    }
    next();
  };
};

/**
 * 基于魔术数字检测文件MIME类型
 * @param {Buffer} buffer - 文件数据缓冲区
 * @returns {string} 检测到的MIME类型
 */
const detectMimeType = (buffer) => {
  // JPEG
  if (buffer.length >= 3 && buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF) {
    return 'image/jpeg';
  }
  // PNG
  if (buffer.length >= 8 && buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) {
    return 'image/png';
  }
  // GIF
  if (buffer.length >= 6 && buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46) {
    return 'image/gif';
  }
  // WebP
  if (buffer.length >= 12 && buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46 &&
      buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50) {
    return 'image/webp';
  }
  // PDF
  if (buffer.length >= 4 && buffer[0] === 0x25 && buffer[1] === 0x50 && buffer[2] === 0x44 && buffer[3] === 0x46) {
    return 'application/pdf';
  }
  // DOC/DOCX
  if (buffer.length >= 8 && ((buffer[0] === 0xD0 && buffer[1] === 0xCF && buffer[2] === 0x11 && buffer[3] === 0xE0 &&
        buffer[4] === 0xA1 && buffer[5] === 0xB1 && buffer[6] === 0x1A && buffer[7] === 0xE1) ||
        (buffer[0] === 0x50 && buffer[1] === 0x4B && buffer[2] === 0x03 && buffer[3] === 0x04))) {
    return 'application/msword';
  }
  // XLS/XLSX
  if (buffer.length >= 8 && ((buffer[0] === 0xD0 && buffer[1] === 0xCF && buffer[2] === 0x11 && buffer[3] === 0xE0 &&
        buffer[4] === 0xA1 && buffer[5] === 0xB1 && buffer[6] === 0x1A && buffer[7] === 0xE1) ||
        (buffer[0] === 0x50 && buffer[1] === 0x4B && buffer[2] === 0x03 && buffer[3] === 0x04))) {
    return 'application/vnd.ms-excel';
  }
  // ZIP
  if (buffer.length >= 4 && buffer[0] === 0x50 && buffer[1] === 0x4B && buffer[2] === 0x03 && buffer[3] === 0x04) {
    return 'application/zip';
  }
  // TXT
  if (buffer.length >= 1) {
    // 简单检测是否为纯文本
    const isText = buffer.every(byte => byte >= 32 && byte <= 126 || [9, 10, 13].includes(byte));
    if (isText) {
      return 'text/plain';
    }
  }
  
  // 默认返回application/octet-stream
  return 'application/octet-stream';
};

/**
 * 恶意文件验证中间件
 * @param {Array} allowedMimeTypes - 允许的MIME类型数组
 * @param {number} maxFileSize - 最大文件大小（字节）
 * @returns {Function} Express中间件函数
 */
const validateFileContent = (allowedMimeTypes = [], maxFileSize = 50 * 1024 * 1024) => {
  return (req, res, next) => {
    // 检查是否有文件
    if (!req.file) {
      return next();
    }

    // 检查文件大小
    if (req.file.size > maxFileSize) {
      logger.warn('文件大小超过限制', { userId: req.user?.id, fileName: req.file.originalname });
      return badRequest(req, res, `文件大小超过限制，最大允许 ${maxFileSize / (1024 * 1024)}MB`);
    }

    try {
      // 读取文件的前几个字节进行魔术数字检测
      const fileBuffer = Buffer.from(fs.readFileSync(req.file.path, { encoding: null, flag: 'r' }));
      
      // 检查文件是否为空
      if (fileBuffer.length === 0) {
        return badRequest(req, res, '不能上传空文件');
      }

      // 检查文件内容是否可能包含恶意脚本（简单的模式匹配）
      const fileContent = fileBuffer.toString('utf8', 0, 1024).toLowerCase();
      const maliciousPatterns = [
        '<script', 'javascript:', 'onerror=', 'onload=',
        'exec(', 'eval(', 'document.cookie', 'alert(',
        'base64_decode', 'system(', 'passthru(', 'shell_exec(',
        'file_put_contents', 'fwrite(', 'fopen(', 'include(',
        'require(', 'import(', 'from ', '__import__('
      ];

      // 对于文本文件进行恶意内容检测
      const isTextFile = req.file.mimetype.includes('text/') || 
                         ['.txt', '.html', '.js', '.css', '.php', '.py', '.sh', '.bat', '.cmd'].some(ext => 
                         req.file.originalname.toLowerCase().endsWith(ext));
      
      if (isTextFile) {
        const detectedPattern = maliciousPatterns.find(pattern => fileContent.includes(pattern));
        if (detectedPattern) {
          logger.warn('检测到可能的恶意文件内容', { userId: req.user?.id, fileName: req.file.originalname, pattern: detectedPattern });
          return badRequest(req, res, '文件内容包含不允许的代码或脚本');
        }
      }

      // 魔术数字检测 - 验证文件真实类型
      const fileMimeType = detectMimeType(fileBuffer);
      if (allowedMimeTypes.length > 0 && !allowedMimeTypes.includes(fileMimeType)) {
        logger.warn('文件类型不匹配', { userId: req.user?.id, fileName: req.file.originalname, detectedType: fileMimeType });
        return badRequest(req, res, `文件类型不允许，检测到的类型: ${fileMimeType}`);
      }

      next();
    } catch (err) {
      logger.error('文件内容验证失败', { userId: req.user?.id, error: err.message });
      return serverError(req, res, '文件验证失败，请稍后重试');
    }
  };
};

module.exports = {
  ensureUploadDir,
  uploadWrapper,
  validateFileSize,
  ensureFileExists,
  validateFileContent,
  detectMimeType,
  extractFileHash: () => {
    return (req, res, next) => {
      try {
        let fileHash = null;
        const headers = (config.upload?.hash?.headers) || [];
        const bodyFields = (config.upload?.hash?.bodyFields) || [];
        const queryFields = (config.upload?.hash?.queryFields) || [];

        for (const h of headers) {
          if (req.headers && req.headers[h]) { fileHash = req.headers[h]; break; }
        }
        if (!fileHash && req.body && typeof req.body === 'object') {
          for (const f of bodyFields) {
            if (req.body[f]) { fileHash = req.body[f]; break; }
          }
          if (!fileHash && req.body.file && req.body.file.hash) {
            fileHash = req.body.file.hash;
          }
        }
        if (!fileHash && req.query && typeof req.query === 'object') {
          for (const f of queryFields) {
            if (req.query[f]) { fileHash = req.query[f]; break; }
          }
        }

        if (fileHash) {
          req.fileHash = String(fileHash).trim();
          logger.info('提取文件hash', { userId: req.user?.id, fileHash: req.fileHash });
        }
        next();
      } catch (err) {
        logger.warn('提取文件hash失败', { error: err.message });
        next();
      }
    };
  },
  parseUploadFields: () => {
    return (req, res, next) => {
      multer().none()(req, res, (err) => {
        if (err) return next(err);
        next();
      });
    };
  }
};